#!/usr/bin/python
# _*_ coding: utf-8 _*_

"""
前程无忧全国招聘信息爬虫
"""
import time
import json
import random
import sqlite3
from retrying import retry  # 重试库
from playwright.sync_api import sync_playwright, Page  # 模拟浏览器访问网页的库
import subprocess

# 前程无忧招聘网站，
total_page = 50   #  设置爬取页数，建议少于30页



# 判断是否存在数据库，不存在则创建
conn = sqlite3.connect("job_info.db")  # 本地数据库文件   原始为：job_info4.db
cursor = conn.cursor()
check_sql = "SELECT * FROM sqlite_master where type='table' and name='job'"
cursor.execute(check_sql)
results = cursor.fetchall()
# 数据库表不存在
if len(results) == 0:
    # 创建数据库表
    sql = """
            CREATE TABLE job(
                job_name CHAR(256),
                hangye CHAR(256),
                company CHAR(256),
                province CHAR(64),
                city CHAR(64),
                salary CHAR(64),
                jingyan CHAR(64),
                xueli CHAR(64),
                zhaopin_counts CHAR(64),
                pub_time CHAR(256)
            );
            """
    cursor.execute(sql)
    conn.commit()
    print("创建数据库表成功！")



# 学历要求
degree_codes = {
    "初中及以下": "01",
    "高中/中技/中专": "02",
    "大专": "03",
    "本科": "04",
    "硕士": "05",
    "博士": "06",
    "无学历要求": "07",
}


@retry(
    stop_max_attempt_number=10,  # 最多重试10次
    retry_on_result=lambda x: x is None,  # 函数get_one_page返回值是None时重试
    wait_fixed=3000,  # 每次重试间隔3s
)
def get_one_page(page: Page, url: str):
    page.goto(url)  # 浏览器页面打开网页url
    dropbutton = page.locator("#nc_1_n1z")  # 定位滑动块元素
    box = dropbutton.bounding_box() # 找到滑动块的边界
    x, y = box["x"] + box["width"] / 2, box["y"] + box["height"] / 2
    page.mouse.move(x, y)  # 将鼠标移动到滑动块内部（x， y）处
    page.mouse.down()  # 按下鼠标准备拖拽滑块
    span = page.locator("#nc_1__scale_text")  # 定位整个滑块条元素
    width = span.bounding_box()["width"]  # 拿到滑块条的长度 - 滑块需要向右移动的长度
    for i in range(1, 31):  # 默认30次
        x += width * i / 30  # 每次移动 width / 30, 第i次的x坐标
        new_x = x + random.uniform(-5, 5)  # random.uniform添加随机值, 模拟手的抖动
        new_y = y + random.uniform(-5, 5)  # 横向移动, y坐标保持不变
        page.mouse.move(new_x, new_y)  # 鼠标移动
        page.wait_for_timeout(random.uniform(20, 100))  # 等待20 - 100 ms
    page.mouse.up()  # 抬起鼠标左键
    page.wait_for_load_state()  # 验证通过后，界面需要刷新，等待
    page.wait_for_timeout(1000)  # 预留1000ms，等待页面元素都加载完毕
    html = page.locator("xpath=/html/body/pre")  # 找到页面html内的<body>元素
    qwer = html.inner_text()  # 拿到<body>内的所有文本内容 -> json字符串

    if "resultbody" in qwer:  # 数据内有resultbody时, 解析为json字典
        return json.loads(qwer)

    # 如果没有resultbody，函数返回None, 满足@retry的重试条件，因此需要重试


if __name__ == "__main__":
    # 定义要执行的命令
    command = r'"C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222'

    # 使用 subprocess.Popen 打开命令提示符并执行命令
    try:
        # 启动 Chrome 浏览器
        subprocess.Popen(command, shell=True)
        print("Chrome 浏览器已启动，远程调试端口已打开。")
    except Exception as e:
        print(f"启动 Chrome 浏览器时出错: {e}")

    with sync_playwright() as p:

        browser = p.chromium.connect_over_cdp("http://127.0.0.1:9222")

        context = browser.new_context()
        browser_page = context.new_page()  # 打开新标签页

        total_count = 0
        keyword = "算法工程师"  # 采集的关键词

        # 数据分析师
        # 前端工程师
        # 后端工程师
        # 测试工程师
        # 大数据分析师
        # 网络工程师
        # 移动应用开发工程师
        # 运维工程师
        # 网络安全工程师
        # 算法工程师

        # 原始代码
        for page in range(1, total_page + 1):  # 总计50页，循环访问
            datas = []
            timestamp = "{:06d}".format(int(time.time()))  # 当前时间戳

            url = f"https://we.51job.com/api/job/search-pc?api_key=51job&timestamp={timestamp}&keyword={keyword}&sortType=3&pageNum={page}&requestId=&pageSize=20&source=1&accountId=&pageCode=sou%7Csou%7Csoulb"
            # url = f"https://we.51job.com/api/job/search-pc?api_key=51job&timestamp={timestamp}&keyword=&searchType=2&function=&industry=&jobArea=000000&jobArea2=&landmark=&metro=&salary=&workYear=&degree=&companyType=&companySize=&jobType=&issueDate=&sortType=3&pageNum={page}&requestId=&pageSize=20&source=1&accountId=&pageCode=sou%7Csou%7Csoulb"


            print(f"--> 爬取第 {page} 页: {url}")
            print(url)
            try:
                data = get_one_page(browser_page, url)  # 在火狐浏览器中验证滑块后，解析数据
            except BaseException as exc:
                print(f"Found exc in {url}: {exc}")
            else:
                items = data["resultbody"]["job"]["items"]  # 目标字段
                for item in items:
                    try:
                        job_name = item["jobName"]
                        hangye = item["industryType1Str"]
                        company = item["companyName"]
                        salary = item["provideSalaryString"]

                        province = item["jobAreaLevelDetail"]["provinceString"]
                        city = item["jobAreaLevelDetail"]["cityString"]

                        jingyan = item["workYearString"]
                        xueli = item["degreeString"]
                        zhaopin_counts = 1  # item['attribute_text'][3]
                        pub_time = item["confirmDateString"]
                        datas.append(
                            (
                                job_name,
                                hangye,
                                company,
                                province,
                                city,
                                salary,
                                jingyan,
                                xueli,
                                zhaopin_counts,
                                pub_time,
                            )
                        )
                    except:
                        print(url)

                total_count += len(datas)
                print("爬取了 {} 条就业数据".format(total_count))
                if datas:  # 如果data列表不为空, 插入到sqlite数据库中
                    insert_sql = "INSERT INTO job(job_name, hangye, company, province, city, salary, jingyan, xueli, zhaopin_counts, pub_time) VALUES (?,?,?,?,?,?,?,?,?,?);"
                    print("数据存储完成！")
                    # 调用函数执行SQL语句，将数据插入到数据库
                    cursor.executemany(insert_sql, datas)
                    conn.commit()  # 提交数据库的写操作， 类似于刷盘操作，写入确认

            time.sleep(5)  # 每一次网络请求【爬虫】后等待5s，防止请求过于频繁，被网站识别为爬虫程序，封掉IP

        context.close()
        browser.close()  # 关闭浏览器
